package com.example.glboardtest1;

import java.util.Random;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;



import android.content.Context;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;

public class GLRenderer implements Renderer{

	private Board 	board;	// the triangle to be drawn
	Random rand = new Random();
	int angle = 0;
	
	private Pieces 		pieces;		// the square
	private Context 	context;
	
	private Cursor cursor = new Cursor();
	
	private float touchX = 0.0f;
	private float touchY = 0.0f;
	private float touchZ = 0.0f;

	private float w_screen;
	private float h_screen;
	private float fovy;
	private float zFar;
	private float zNear;
	
	private float zMoved;
	private double[] angleError = new double[2];
	private int[] resultRowColumn = new int[2];
	private boolean touched;
	private int[] rc = {0,0};
	private double board_tilt = 35;
	private float screenX;
	private float screenY;
	
	/** Constructor to set the handed over context */
	public GLRenderer(Context context) {
		this.board = new Board();
		
		this.context = context;
		
		// initialise the square
		this.pieces = new Pieces();

		
	}
	
	
	
	
	@Override
	public void onDrawFrame(GL10 gl) {

		cursor.reset();

		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

		// moving along negative z axis - same as moving camera
		zMoved = 6.0f;

		angle++;
		
		drawBoardTest(gl);
		
//		touchTestCartesian(gl);

		touchTestPsherical(gl);
		
//		drawPieceOn(gl,-3,-3);
		
//		drawPieceOn(gl,-2,-2);
//		
//		drawPieceOn(gl,-1,-1);
//		
//		drawPieceOn(gl,0,0);
//		
//		drawPieceOn(gl, 1, 1);
//		
//		drawPieceOn(gl, 2, 2);
//		
//		drawPieceOn(gl, 3, 3);
		
//		drawPieceOn(gl, 166.96985968593268*Math.PI/180, 149.03624346792648*Math.PI/180, 12.931029244958978);
		
//		drawPieceOn(gl, 171.26411569079946*Math.PI/180, 146.30993247402023*Math.PI/180, 11.869752386992563);

//		drawPieceOn(gl, 176.27673724084212*Math.PI/180, 135.0*Math.PI/180, 10.889008017513293);
		
//		drawPieceOn(gl, 177.1375947738881*Math.PI/180, 0.0*Math.PI/180, 10.012492197250394);

	}
		
	private void drawPieceOn(GL10 gl, int row, int column){
		float[] x = fieldXYZ(row, column);
		double[] a = fieldRollPitch(x);
		
		gl.glLoadIdentity();
		gl.glTranslatef(x[0], x[1], x[2]);
		pieces.draw(gl);
		
		Log.i("", "pitch : " + a[0]*180/Math.PI + " roll : " + a[1]*180/Math.PI  + " r : " +  Math.sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]));
	}
	
	
	private void drawPieceOn(GL10 gl, double pitch, double roll, double r){
		float x = (float)(Math.sin(pitch)*Math.cos(roll)*r);
		float y = (float)(Math.sin(pitch)*Math.sin(roll)*r);
		float z = (float)(Math.cos(pitch)*r);
		
		gl.glLoadIdentity();
		gl.glTranslatef(x, y, z);
		pieces.draw(gl);
		
		Log.i("", "x : " + x + " y : " + y  + " z : " +  z);
		
	}
	
	
	
	private void drawBoardTest(GL10 gl) {
		// Reset the Modelview Matrix
		gl.glLoadIdentity();
		gl.glTranslatef(0.0f, 0.0f, -(zMoved));		// move 5 units INTO the screen

		//board seen from 30 deg 
		gl.glRotatef((float) board_tilt, 1, 0, 0);
		
		gl.glRotatef(angle, 0, 1, 0);
		
		board.draw(gl, cursor);
	}

	
	
	//Needed methods
	//0.) drawTouchedField(roll,pitch)
	//
	//1.) x,y,z			= fieldXYZ(row,column)
	//
	//2.) roll,pitch	= fieldRollPitch(x,y,z)
	//
	//3.) x,y,z			= getField(roll,pitch)

	

	
	private float[] fieldXYZ(int row, int column){
		float x_board = column*1.0f;
		float y_board = 0.0f;
		float z_board = row*1.0f;
				
		float phi   = (float) ((Math.PI/180.0f)*board_tilt);		//x
		float theta   = (float) ((Math.PI/180.0f)*angle);	//y
		
		float r11 = (float) (Math.cos(theta));
		float r12 = 0;
		float r13 = (float) (Math.sin(theta));
		
		float r21 = (float) (Math.sin(theta)*Math.sin(phi));
		float r22 = (float) (Math.cos(theta));
		float r23 = (float) (-Math.sin(phi)*Math.cos(theta));
		
		float r31 = (float) (-Math.cos(phi)*Math.sin(theta));
		float r32 = (float) (Math.sin(phi));
		float r33 = (float) (Math.cos(phi)*Math.cos(theta));
		
		//addition because of camera movement
		float x = r11*x_board + r12*y_board + r13*z_board ;//+    0.5f; 
		float y = r21*x_board + r22*y_board + r23*z_board;
		float z = r31*x_board + r32*y_board + r33*z_board -    zMoved;
		
		
		float[] result = {x,y,z};
		
		return result;
	}
	
	private double[] fieldRollPitch(float[] xyz){
		double r = Math.sqrt(xyz[0]*xyz[0] + xyz[1]*xyz[1] + xyz[2]*xyz[2]);

		double pitch = Math.acos(xyz[2]/r);
		
		double roll= Math.atan2(xyz[1], xyz[0]);
		
		double[] result = {pitch,roll};
		
		return result;
	}
	
	private int[] fieldXYZ(double[] ang){
		double error = 1000;
		double e = 1000;
		
		double offset = 20;
		
		if((screenX<=(w_screen/2 + offset) && screenX>=(w_screen/2 - offset)) &&  (screenY<=(h_screen/2 + offset) && screenY>=(h_screen/2 - offset)) ){
			resultRowColumn[0] = 0;
			resultRowColumn[1] = 0;
			
			return resultRowColumn;
			
		}
		
		
		
		for(int row=-10; row < 10; row++){
			for(int column=-10; column < 10 ; column++){
				float[] xyz = fieldXYZ(row,column);
//				xyz[0] = xyz[0]-0.5f;
//				xyz[1] = xyz[1]-0.5f;
 				
				double[] angels = fieldRollPitch(xyz);
				e = Math.abs(angels[1] - ang[1]) + Math.abs(angels[0] - ang[0]);
				
				if(e<error && 
						Math.abs(angels[1] - ang[1])*180/Math.PI < 10 && 
							Math.abs(angels[0] - ang[0])*180/Math.PI < 10){
					
					error = e;
					
					resultRowColumn[0]  = row;
					resultRowColumn[1]  = column;
					
					angleError [0] = (angels[0] - ang[0]);
					angleError[1] = (angels[1] - ang[1]);
				}
			}
		}
		
		Log.i("Match", "pitchE : " + angleError[0]*180/Math.PI   + " rollE: " + angleError[1]*180/Math.PI );

		return resultRowColumn;
	}
	
	
	private void touchTestPsherical(GL10 gl){

		if(touched){
		double r = Math.sqrt(touchX*touchX + touchY*touchY + touchZ*touchZ);
		double pitch = Math.acos(touchZ/r);		
		double roll = Math.atan2(touchY, touchX);
		
//		r = 5;
//		float x2 = (float)(Math.sin(pitch)*Math.cos(roll)*r);
//		float y2 = (float)(Math.sin(pitch)*Math.sin(roll)*r);
//		float z2 = (float)(Math.cos(pitch)*r);
		
		rc =fieldXYZ(new double[]{pitch,roll});
		
		touched= false;
		}
		
		
		
		float[] xx = fieldXYZ(rc[0],rc[1]);
		float x2 = xx[0];
		float y2 = xx[1];
		float z2 = xx[2];
		
		
		gl.glLoadIdentity();
		gl.glTranslatef(x2 + .5f, y2, z2);
		
//		Log.i("Touch", "pitchT : " + pitch*180/Math.PI + " rollT : " + roll*180/Math.PI);
		Log.i("", "TouchY : " + touchY);
		pieces.draw(gl);
		
	}


	private void touchTestCartesian(GL10 gl) {
		float z = touchZ;
		float x = touchX;
		float y = touchY;
		
		gl.glLoadIdentity();
		gl.glTranslatef(x, y, z);
		
		//		Log.i("cursor square-", " x :" + x + "touchY :" + y + " z:" + z);
		
		pieces.draw(gl);
	}
	
	
	


	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		if(height == 0) { 						//Prevent A Divide By Zero By
			height = 1; 						//Making Height Equal One
		}

		w_screen = width;
		h_screen = height;
		
		fovy = 45.0f;
		
		zFar = 50.0f;
	
		zNear = 0.1f;
		
		gl.glViewport(0, 0, width, height); 	//Reset The Current Viewport
		gl.glMatrixMode(GL10.GL_PROJECTION); 	//Select The Projection Matrix
		gl.glLoadIdentity(); 					//Reset The Projection Matrix

		//Calculate The Aspect Ratio Of The Window
		GLU.gluPerspective(gl, fovy, (float)width / (float)height, zNear, zFar);

		
		
		gl.glMatrixMode(GL10.GL_MODELVIEW); 	//Select The Modelview Matrix
		gl.glLoadIdentity(); 					//Reset The Modelview Matrix
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// Load the texture for the square
		pieces.loadGLTexture(gl, this.context);
		
//		board.loadGLTexture(gl, this.context);
		
			//Enable Texture Mapping ( NEW )
		gl.glShadeModel(GL10.GL_SMOOTH); 			//Enable Smooth Shading
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 	//Black Background
		gl.glClearDepthf(-10.0f); 					//Depth Buffer Setup
		gl.glEnable(GL10.GL_DEPTH_TEST); 			//Enables Depth Testing
		gl.glDepthFunc(GL10.GL_LEQUAL); 			//The Type Of Depth Testing To Do
		
		gl.glEnable( gl.GL_ALPHA_TEST );			// transparent texture background
		gl.glAlphaFunc( gl.GL_GREATER, 0 );

		
		//		
//		//Really Nice Perspective Calculations
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
//		gl.glDisable(GL10.GL_TEXTURE_2D);
	}




	public void handleTouch(MotionEvent event) {
		// TODO Auto-generated method stub
		float L = zFar + zNear;
		float v = fovy;
		
		float h_far = 2.0f*L*(float)Math.sin((Math.PI/180.0f)*(v/2.0f));
		float w_far = w_screen/h_screen*h_far;
		
		screenX = event.getX();
		screenY = event.getY();
		
		touchX 	= event.getX()*w_far/w_screen - w_far/2;
		touchY 	= -(event.getY()*h_far/h_screen - h_far/2);
		touchZ  = -zFar;
		
		touched = true;
	}

	
	
}
